import { Request, Response, NextFunction } from 'express';
import { Logger } from '@/utils/logger';

export class AppError extends Error {
  public statusCode: number;
  public status: string;
  public isOperational: boolean;
  public code?: string;

  constructor(message: string, statusCode: number = 500, code?: string) {
    super(message);
    this.statusCode = statusCode;
    this.status = `${statusCode}`.startsWith('4') ? 'fail' : 'error';
    this.isOperational = true;
    this.code = code;

    Error.captureStackTrace(this, this.constructor);
  }
}

export class ValidationError extends AppError {
  constructor(message: string, field?: string) {
    super(message, 400, 'VALIDATION_ERROR');
    this.name = 'ValidationError';
  }
}

export class AuthenticationError extends AppError {
  constructor(message: string = '身份验证失败') {
    super(message, 401, 'AUTHENTICATION_ERROR');
    this.name = 'AuthenticationError';
  }
}

export class AuthorizationError extends AppError {
  constructor(message: string = '权限不足') {
    super(message, 403, 'AUTHORIZATION_ERROR');
    this.name = 'AuthorizationError';
  }
}

export class NotFoundError extends AppError {
  constructor(message: string = '资源未找到') {
    super(message, 404, 'NOT_FOUND_ERROR');
    this.name = 'NotFoundError';
  }
}

export class ConflictError extends AppError {
  constructor(message: string) {
    super(message, 409, 'CONFLICT_ERROR');
    this.name = 'ConflictError';
  }
}

export class RateLimitError extends AppError {
  constructor(message: string = '请求过于频繁，请稍后重试') {
    super(message, 429, 'RATE_LIMIT_ERROR');
    this.name = 'RateLimitError';
  }
}

const logger = new Logger('ErrorHandler');

export const errorHandler = (
  error: Error | AppError,
  req: Request,
  res: Response,
  next: NextFunction
): void => {
  let statusCode = 500;
  let message = '服务器内部错误';
  let code = 'INTERNAL_ERROR';

  // 处理不同类型的错误
  if (error instanceof AppError) {
    statusCode = error.statusCode;
    message = error.message;
    code = error.code || 'APP_ERROR';
  } else if (error.name === 'ValidationError') {
    statusCode = 400;
    message = '请求参数验证失败';
    code = 'VALIDATION_ERROR';
  } else if (error.name === 'JsonWebTokenError') {
    statusCode = 401;
    message = '无效的访问令牌';
    code = 'INVALID_TOKEN';
  } else if (error.name === 'TokenExpiredError') {
    statusCode = 401;
    message = '访问令牌已过期';
    code = 'TOKEN_EXPIRED';
  } else if (error.name === 'CastError') {
    statusCode = 400;
    message = '无效的请求参数格式';
    code = 'INVALID_FORMAT';
  } else if (error.name === 'MongoError' && (error as any).code === 11000) {
    statusCode = 409;
    message = '数据已存在';
    code = 'DUPLICATE_ERROR';
  }

  // 记录错误日志
  const errorInfo = {
    requestId: req.headers['x-request-id'],
    method: req.method,
    url: req.originalUrl,
    ip: req.ip,
    userAgent: req.get('User-Agent'),
    statusCode,
    message,
    code,
    stack: error.stack
  };

  if (statusCode >= 500) {
    logger.error('Server error occurred', errorInfo);
  } else {
    logger.warn('Client error occurred', errorInfo);
  }

  // 响应错误信息
  const response: any = {
    success: false,
    error: {
      code,
      message
    },
    timestamp: new Date().toISOString(),
    path: req.originalUrl
  };

  // 开发环境下包含更多调试信息
  if (process.env.NODE_ENV === 'development') {
    response.error.stack = error.stack;
    response.error.details = error;
  }

  res.status(statusCode).json(response);
};

// 未捕获异常处理
export const handleUncaughtException = (): void => {
  process.on('uncaughtException', (error: Error) => {
    logger.error('Uncaught Exception:', {
      message: error.message,
      stack: error.stack
    });
    
    // 优雅关闭
    process.exit(1);
  });
};

// 未处理的Promise拒绝
export const handleUnhandledRejection = (): void => {
  process.on('unhandledRejection', (reason: any, promise: Promise<any>) => {
    logger.error('Unhandled Rejection:', {
      reason: reason?.message || reason,
      stack: reason?.stack,
      promise: promise.toString()
    });
    
    // 优雅关闭
    process.exit(1);
  });
};

// 异步错误包装器
export const asyncHandler = (fn: Function) => {
  return (req: Request, res: Response, next: NextFunction) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};